package afcp.alumni.csv;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import afcp.alumni.model.CsvFileProperties;
import afcp.alumni.model.db.Login;
import afcp.alumni.model.db.Member;
import afcp.alumni.service.MemberService;
import afcp.alumni.service.SF;

public class MemberReader /*extends CSVReader*/ implements Iterable<Member> {

	private static final Log logger = LogFactory.getLog(MemberReader.class);

	private CsvFileProperties file;
	
	private FileReader reader;

	public MemberReader(Reader reader, CsvFileProperties file) throws IOException,
			IncorrectCSVHeaderException {
//		super(reader, file.getSeparator(), file.getQuote(), file.getEscape());
		this.file = file;
		this.reader = new CSVReader(reader, file.getSeparator(), file.getQuote(), file.getEscape());
		checkHeaders();
	}

	public MemberReader(InputStream inputStream, CsvFileProperties file)
			throws IncorrectCSVHeaderException, IOException {
//		super(new InputStreamReader(inputStream, file.getCharsetObj()), file
//				.getSeparator(), file.getQuote(), file.getEscape());
		this.file = file;
		this.reader = new CSVReader(new InputStreamReader(inputStream, file.getCharsetObj()), file
				.getSeparator(), file.getQuote(), file.getEscape());
		checkHeaders();
	}

	private int firstNameIdx = -1;
	private int lastNameIdx = -1;
	private int loginIdx = -1;
	private int passwordIdx = -1;

	private void checkHeaders() throws IOException, IncorrectCSVHeaderException {
		String[] headers = reader.readNext();

		Map<String, String> expHeaders = file.getHeaders();
		Map<String, String> invExpHeaders = new HashMap<>();
		for (Entry<String, String> e : expHeaders.entrySet()) {
			invExpHeaders.put(e.getValue(), e.getKey());
		}

		int i = 0;
		for (String header : headers) {
			String value = invExpHeaders.get(header);
			if (value != null) {
				switch (value) {
				case Member.COL_FIRSTNAME:
					firstNameIdx = i;
					break;
				case Member.COL_LASTNAME:
					lastNameIdx = i;
					break;
				case Member.COL_LOGIN:
					loginIdx = i;
					break;
				case Member.COL_PASSWORD:
					passwordIdx = i;
					break;
				}
			}
			i++;
		}

		if (firstNameIdx == -1 || lastNameIdx == -1 || loginIdx == -1
				|| passwordIdx == -1) {
			throw new IncorrectCSVHeaderException(headers, expHeaders.values());
		}
	}

	private MemberService memberService = SF.member();

	private boolean iterated = false;

	@Override
	public Iterator<Member> iterator() {
		if (iterated) {
			throw new UnsupportedOperationException(
					"Can't get two iterators of MemberCSVReader. "
					+ "This reader can be read only once.");
		}
		iterated = true;
		return new MemberCsvIterator();
	}

	public void close() throws IOException {
		reader.close();
	}

	private class MemberCsvIterator implements Iterator<Member> {

		private Member next = null;

		@Override
		public boolean hasNext() {
			if (next == null) {
				next = readNextMember();
			}
			return next != null;
		}

		private long i = 0;

		private Member readNextMember() {
			String[] line = null;
			try {
				boolean loop = false;
				do {
					i++;
					line = MemberReader.this.reader.readNext();
					if (line == null) {
						return null;
					}
					loop = line.length < Member.defaultColumns.length;
					if (loop) {
						logger.error("La ligne " + i
								+ " du fichier CSV a un format incorrect. "
								+ "Contenu trouvé après analyse: "
								+ lineArrayToString(line));
					}
				} while (line != null && loop);
			} catch (IOException e) {
				logger.error(
						"A problem occurred while trying to read the member "
						+ "on the uploaded file or while trying to add it "
						+ "to the datastore.",
						e);
				return null;
			}
			Member member = new Member();
			String firstName = line[firstNameIdx];
			String lastName = line[lastNameIdx];
			Login login = new Login(line[loginIdx], member);
			String password = line[passwordIdx];
//			member.setId(login);
			member.setLogin(login);
			member.setPassword(password);
			member.setFirstName(firstName);
			member.setLastName(lastName);
			member.setDeletable(true);
			member.setRole(memberService.getRoleMember());

			return member;
		}

		private String lineArrayToString(String[] line) {
			StringBuilder lineBuilder = new StringBuilder();
			boolean first = true;
			for (String col : line) {
				if (first) {
					lineBuilder.append(", ");
				} else {
					first = false;
				}
				lineBuilder.append(col);
			}
			return lineBuilder.toString();
		}

		@Override
		public Member next() {
			if (next != null) {
				Member result = next;
				next = null;
				return result;
			} else {
				return readNextMember();
			}
		}

		@Override
		public void remove() {
			throw new UnsupportedOperationException(
					"Can't remove entries in uploaded CSV file.");
		}

	}

}
